package cn.i7baozh.starter.client.loadbalancer;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.balancer.NacosBalancer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 通过远程配置动态拉取相同分组的服务列表
 *
 * @author : baoqi.zhang
 * @date :   2022/5/12 20:14
 */
public class SameClusterGroupGroupLoadBalancer implements ReactorServiceInstanceLoadBalancer {

    private static final Logger log = LoggerFactory.getLogger(SameClusterGroupGroupLoadBalancer.class);

    private final String serviceId;

    private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
    private final NacosDiscoveryProperties nacosDiscoveryProperties;

    public SameClusterGroupGroupLoadBalancer(
            ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider,
            String serviceId,
            NacosDiscoveryProperties nacosDiscoveryProperties
    ) {
        this.serviceId = serviceId;
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
        this.nacosDiscoveryProperties = nacosDiscoveryProperties;
    }

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
                .getIfAvailable(NoopServiceInstanceListSupplier::new);
        //获取当前可用的服务组信息
        String availableServiceGroup = this.nacosDiscoveryProperties.getMetadata().get("i7baozh_group");
//        log.info("envHeader:{}, group:{}", availableServiceGroup, group);
        return supplier.get().next().map(serviceInstance -> getInstanceResponse(serviceInstance, availableServiceGroup));
    }

    private Response<ServiceInstance> getInstanceResponse(
            List<ServiceInstance> serviceInstances, String availableServiceGroup) {
        if (serviceInstances.isEmpty()) {
            log.warn("No servers available for service: " + this.serviceId);
            return new EmptyResponse();
        }

        try {
            List<ServiceInstance> instancesToChoose = null;
            if (StringUtils.isNotBlank(availableServiceGroup)) {
                instancesToChoose = serviceInstances.stream()
                        .filter(serviceInstance -> {
                            String cluster = serviceInstance.getMetadata()
                                    .get("i7baozh_group");
                            return StringUtils.equals(cluster, availableServiceGroup);
                        }).collect(Collectors.toList());
            }
            if (CollectionUtils.isEmpty(instancesToChoose)) {
                return null;
            }

            ServiceInstance instance = NacosBalancer
                    .getHostByRandomWeight3(instancesToChoose);

            return new DefaultResponse(instance);
        } catch (Exception e) {
            log.warn("NacosLoadBalancer error", e);
            return null;
        }

    }
}
